

package cn.shengchao.examstar.product.acl.adapters.repositories;

import cn.hutool.core.util.StrUtil;
import cn.shengchao.base.enums.DisEnableStatusEnum;
import cn.shengchao.examstar.comment.acl.ports.repositories.message.CourseListDto;
import cn.shengchao.examstar.product.acl.adapters.repositories.factories.*;
import cn.shengchao.examstar.product.acl.ports.repositories.IProductRepository;
import cn.shengchao.examstar.product.domain.entity.Course;
import cn.shengchao.examstar.product.domain.entity.CourseKnowledgeNode;
import cn.shengchao.examstar.product.domain.entity.Product;
import cn.shengchao.examstar.product.domain.entity.Teacher;
import cn.shengchao.examstar.product.infrastructure.dao.*;
import cn.shengchao.examstar.product.infrastructure.dao.po.*;
import cn.shengchao.examstar.product.ohs.local.appservice.ProductAppService;
import cn.shengchao.examstar.rpc.product.req.CourseQueryPage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Repository
public class ProductRepository implements IProductRepository {

    private ProductCourseDao productCourseDao;

    @Autowired
    private ProductCourseNodesDao productCourseNodesDao;

    @Autowired
    private TProductMemberDao tProductMemberDao;
    @Autowired
    private TProductThirdCapDao tProductThirdCapDao;
    @Autowired
    private TProductThirdYcbdcDao tProductThirdYcbdcDao;

    @Autowired
    private TProductSpecificationTypeDao tProductSpecificationTypeDao;

    ProductAppService productAppService;

    public ProductRepository(ProductCourseDao productCourseDao) {
        this.productCourseDao = productCourseDao;
    }

    @Override
    public Optional<Product> findById(Long id) {
        TProductCourse productCourse = productCourseDao.selectById(id);
        List<TProductSpecificationType> specificationTypes = tProductSpecificationTypeDao.selectList(new LambdaQueryWrapper<TProductSpecificationType>()
                .eq(TProductSpecificationType::getProductId, id));
        if (!specificationTypes.isEmpty()) {
            productCourse.setSpecificationType(String.join(",", specificationTypes.stream()
                    .map(item -> String.valueOf(item.getSpecificationType())).toList()));
        }
        if (productCourse != null) {
            if (productCourse.getDeleted() == 1) {
                return Optional.empty();
            }
            return Optional.of(new CourseFactory().createProduct(productCourse));
        }
        TProductCourseNodes productCourseKnowledgeNode = productCourseNodesDao.selectById(id);
        if (productCourseKnowledgeNode != null) {
            if (productCourseKnowledgeNode.getDeleted() == 1) {
                return Optional.empty();
            }
            return Optional.of(new CourseKnowledgeNodeFactory().createProduct(productCourseKnowledgeNode));
        }
        TProductMember tProductMember = tProductMemberDao.selectById(id);
        if (tProductMember != null) {
            if (tProductMember.getDeleted() == 1) {
                return Optional.empty();
            }
            return Optional.of(new ProductMemberFactory().createProduct(tProductMember));
        }

        TProductThirdCap tProductThirdCap = tProductThirdCapDao.selectById(id);
        if (tProductThirdCap != null) {
            if (tProductThirdCap.getDeleted() == 1) {
                return Optional.empty();
            }
            return Optional.of(new ProductThirdCapFactory().createProduct(tProductThirdCap));
        }
        TProductThirdYcbdc tProductThirdYcbdc = tProductThirdYcbdcDao.selectById(id);
        if (tProductThirdYcbdc != null) {
            if (tProductThirdYcbdc.getDeleted() == 1) {
                return Optional.empty();
            }
            return Optional.of(new ProductThirdYcbdcFactory().createProduct(tProductThirdYcbdc));
        }
        return Optional.empty();
    }

    @Override
    public List<Course> findCourseByProductNameAndSpecifications(String productName, String specifications, List<Long> ids) {
        List<TProductCourse> productCourses = productCourseDao.selectList(new LambdaQueryWrapper<TProductCourse>()
                .like(StrUtil.isNotEmpty(productName), TProductCourse::getName, productName)
                .in(!ids.isEmpty(), TProductCourse::getId, ids)
                .eq(TProductCourse::getStatus, DisEnableStatusEnum.ENABLE)
                .eq(TProductCourse::getDeleted, 0)
                .last(" order by specification_type,sort asc , id desc"));
        return productCourses.stream()
                .map(productCourse -> new CourseFactory().createThumbnailProduct(productCourse))
                .collect(Collectors.toList());
    }

    @Override
    public List<Course> findCourseByIds(List<Long> ids) {
        List<TProductCourse> productCourses = productCourseDao.selectList(new LambdaQueryWrapper<TProductCourse>()
                .in(TProductCourse::getId, ids)
                .eq(TProductCourse::getStatus, DisEnableStatusEnum.ENABLE)
                .eq(TProductCourse::getDeleted, 0)
                .orderByDesc(TProductCourse::getSort));
        List<Course> courses = productCourses.stream()
                .map(productCourse -> new CourseFactory().createThumbnailProduct(productCourse))
                .toList();
        //组装知识点
        List<CompletableFuture<Course>> completableFutures = courses.stream()
                .map(course -> CompletableFuture.supplyAsync(() -> {
                    course.setKnowledgeNodes(this.findListByCourseId(course.getId(), "", true));
                    return course;
                }))
                .toList();
        CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).join();
        return courses;
    }

    @Override
    public List<Long> findCourseIdByTeacherId(Long teacherId) {
        List<TProductCourseNodes> productCourseKnowledgeNodes = productCourseNodesDao
                .selectList(new LambdaQueryWrapper<TProductCourseNodes>().eq(TProductCourseNodes::getTeacherId, teacherId)
                        .eq(TProductCourseNodes::getDeleted, 0)
                );
        return productCourseKnowledgeNodes.stream().map(TProductCourseNodes::getCourseId).distinct().toList();
    }

    @Override
    public List<Teacher> findTeacherByCourseId(Long courseId) {
        List<TProductCourseNodes> productCourseKnowledgeNodes = productCourseNodesDao
                .selectList(new LambdaQueryWrapper<TProductCourseNodes>().eq(TProductCourseNodes::getCourseId, courseId));
        return productCourseKnowledgeNodes.stream()
                .map(item -> Teacher.builder()
                        .id(item.getTeacherId())
                        .name(item.getTeacherName())
                        .headUrl(item.getTeacherHeadUrl())
                        .build())
                .collect(Collectors.toList());
    }

    @Override
    public List<CourseKnowledgeNode> findListByCourseIdByNewOrder(Long courseId, String searchName, boolean isLesson) {
        List<Long> knowledgeIds = productCourseNodesDao.selectCourseSectionByLessonSectionOrderList(courseId.toString(), searchName, isLesson);
        if (knowledgeIds.isEmpty()){
            return List.of();
        }else {
            List<TProductCourseNodes> productCourseKnowledgeNodes =productCourseNodesDao.selectByIds(knowledgeIds);
            List<CompletableFuture<CourseKnowledgeNode>> completableFutures = productCourseKnowledgeNodes.stream()
                    .map(item -> CompletableFuture.supplyAsync(() -> new CourseKnowledgeNodeFactory().createProduct(item)))
                    .toList();
            CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).join();
            return completableFutures.stream().map(item -> {
                try {
                    return item.get();
                } catch (Exception e) {
                    return null;
                }
            }).toList();
        }

    }

    @Override
    public List<CourseKnowledgeNode> findListByCourseId(Long courseId, String searchName, boolean isLesson) {
        List<TProductCourseNodes> productCourseKnowledgeNodes=productCourseNodesDao.findListByCourseId(courseId,searchName,isLesson);
//        List<TProductCourseNodes> productCourseKnowledgeNodes = productCourseNodesDao.selectList(new LambdaQueryWrapper<TProductCourseNodes>().eq(TProductCourseNodes::getCourseId, courseId)
//                        .eq(isLesson, TProductCourseNodes::getIsLesson, isLesson)
//                        .eq(TProductCourseNodes::getDeleted, false)
//                        .like(StrUtil.isNotEmpty(searchName), TProductCourseNodes::getName, searchName)
//                        .orderByAsc(TProductCourseNodes::getSort)
//                        .orderByAsc(TProductCourseNodes::getCreateTime));
        if (!productCourseKnowledgeNodes.isEmpty()) {
            List<CompletableFuture<CourseKnowledgeNode>> completableFutures = productCourseKnowledgeNodes.stream()
                    .map(item -> CompletableFuture.supplyAsync(() -> new CourseKnowledgeNodeFactory().createProduct(item)))
                    .toList();
            CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).join();
            return completableFutures.stream().map(item -> {
                try {
                    return item.get();
                } catch (Exception e) {
                    return null;
                }
            }).toList();
        }
        return List.of();
    }

    @Override
    public CourseKnowledgeNode getKnowledgeNode(Long knowledgeNodeId) {
        TProductCourseNodes productCourseKnowledgeNode = productCourseNodesDao.selectById(knowledgeNodeId);
        return new CourseKnowledgeNodeFactory().createProduct(productCourseKnowledgeNode);
    }

    @Override
    public Map<Long, String> findNameByIds(List<Long> productIds) {
        List<TProductCourse> courses = productCourseDao.selectList(new LambdaQueryWrapper<TProductCourse>()
                .in(TProductCourse::getId, productIds));
        List<TProductCourseNodes> courseKnowledgeNodes = productCourseNodesDao
                .selectList(new LambdaQueryWrapper<TProductCourseNodes>().in(TProductCourseNodes::getId, productIds));
        Map<Long, String> map = new HashMap<>();
        courses.forEach(item -> map.put(item.getId(), item.getName()));
        courseKnowledgeNodes.forEach(item -> map.put(item.getId(), item.getName()));
        return map;
    }

    @Override
    public List<CourseListDto> getCourseList(CourseQueryPage courseQueryPage) {
        List<CourseListDto> courseListDtoList = productCourseDao.findCourseList(courseQueryPage);
        //组装知识点
        List<CompletableFuture<CourseListDto>> completableFutures = courseListDtoList.stream()
                .map(course -> CompletableFuture.supplyAsync(() -> {
                    List<CourseKnowledgeNode> nodes = this.findListByCourseId(course.getId(), "", true);
                    if (nodes != null) {
                        course.setKnowledgeNodeNum(String.valueOf((long) nodes.size()));
                    } else {
                        course.setKnowledgeNodeNum("0");
                    }
                    if (course.getTeacher() != null && course.getTeacher().startsWith(",")) {
                        course.setTeacher(course.getTeacher().substring(1));
                    }
                    return course;
                }))
                .toList();
        CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).join();
        return courseListDtoList;
    }

    @Override
    public Map<String, BigDecimal> sumCourseListPrice(CourseQueryPage courseQueryPage) {
        return productCourseDao.findCourseListSumPrice(courseQueryPage);
    }

    @Override
    public void deleteCourse(Long courseId) {
        TProductCourse productCourse = productCourseDao.selectById(courseId);
        if (productCourse != null) {
            productCourse.setDeleted(1L);
            productCourseDao.updateById(productCourse);
        }
    }

    @Override
    public List<Long> getKnowledgeIds(Long courseId, boolean isLesson) {
        List<TProductCourseNodes> productCourseKnowledgeNodes = productCourseNodesDao
                .selectList(new LambdaQueryWrapper<TProductCourseNodes>().eq(TProductCourseNodes::getCourseId, courseId)
                        .eq(isLesson, TProductCourseNodes::getIsLesson, isLesson)
                        .eq(TProductCourseNodes::getDeleted, false));
        return productCourseKnowledgeNodes.stream().map(TProductCourseNodes::getId).toList();
    }

    @Override
    public List<Long> findCourseIdByTeacherName(String searchValue) {
        List<TProductCourseNodes> nodes = productCourseNodesDao.selectList(new LambdaQueryWrapper<TProductCourseNodes>()
                .like(TProductCourseNodes::getTeacherName, searchValue));
        if (nodes == null || nodes.isEmpty()) {
            return new ArrayList<>();
        }
        return nodes.stream().map(TProductCourseNodes::getCourseId).distinct().toList();
    }

    @Override
    public List<TProductCourseNodes> findCourseNodesByProductIds(List<Long> productIds,boolean isLesson) {
        return productCourseNodesDao.selectList(new LambdaQueryWrapper<TProductCourseNodes>()
                .in(TProductCourseNodes::getId, productIds).eq(TProductCourseNodes::getIsLesson, isLesson?1:0));
    }

    @Override
    public List<Long> findCourseNodesByParentLessonId(Long productId) {
        return productCourseNodesDao.selectCourseLessonByParentLessonId(productId);
    }
}
